package com.dishdex.menuhub.app.controller.dish;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import com.alibaba.excel.EasyExcel;
import com.dishdex.menuhub.app.controller.DishImportListener;
import com.dishdex.menuhub.app.domain.WrapperParameter;
import com.dishdex.menuhub.app.domain.dish.*;
import com.dishdex.menuhub.app.util.DishConverter;
import com.dishdex.menuhub.module.module.category.entity.Category;
import com.dishdex.menuhub.module.module.category.service.CategoryService;
import com.dishdex.menuhub.module.module.dish.entity.Dish;
import com.dishdex.menuhub.module.module.dish.service.DishService;
import com.dishdex.menuhub.module.utils.BaseUtils;
import com.dishdex.menuhub.module.utils.PersonJwt;
import com.dishdex.menuhub.module.utils.Response;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * ClassName:
 * Package: com.dishdex.menuhub.controller
 * Description:
 *
 * @Author:
 * @Create 2025/8/1 15:14
 * @Version 1.0
 */
@RestController
public class DishController {

    @Autowired
    private DishService dishService;

    @Autowired
    private CategoryService categoryService;

    //接口1：用于返回菜品列表
    @RequestMapping("/dish/list")
    public Response dishList(@RequestParam(value = "wp", required = false) String wp,
                             @RequestParam(value = "keyword", required = false) String keyword) {

        int dishPage = 1;
        try {
            if (wp != null && !wp.isEmpty()) {
                WrapperParameter wrapperParam = PersonJwt.unpackString(wp, WrapperParameter.class);
                if (wrapperParam.getDishPage() != null) {
                    dishPage = wrapperParam.getDishPage();
                }
                if (wrapperParam.getKeyword() != null && !wrapperParam.getKeyword().isEmpty()) {
                    keyword = wrapperParam.getKeyword();
                }
            }
        } catch (Exception ex) {
            DishPageVO errorVo = new DishPageVO();
            errorVo.setMessage(ex.getMessage());
            return new Response(4004, errorVo);
        }

        /* 4. 查询当前页数据 */
        List<Dish> dishList = dishService.getAllToAPP(dishPage, keyword);
        List<DishItemVO> voList = new ArrayList<>();
        for (Dish dish : dishList) {
            voList.add(DishConverter.toDishItemVO(dish, categoryService));
        }

        /* 5. 组装返回对象 */
        DishPageVO result = new DishPageVO();
        result.setList(voList);
        result.setIsEnd(dishList.size() < DishService.PAGE_SIZE);

        /* 6. 生成下一次请求的加密参数 */
        WrapperParameter nextParam = new WrapperParameter();
        nextParam.setDishPage(dishPage + 1);
        nextParam.setKeyword(keyword);

        String nextWp = null;
        try {
            nextWp = PersonJwt.packObject(nextParam);
        } catch (Exception ex) {
            DishPageVO errorVo = new DishPageVO();
            errorVo.setMessage(ex.getMessage());
            return new Response(4004, errorVo);
        }
        result.setWp(nextWp);

        return new Response(1001, result);
    }

    //接口2：根据Id返回某个菜品的详细信息
    @RequestMapping("dish/info")
    public Response dishInfo(@RequestParam(value = "dishId", required = false) Long dishId) {
        Dish dish;
        try {
            dish = dishService.getById(dishId);
        } catch (RuntimeException e) {
            DishDetailVO dishDetailVO = new DishDetailVO();
            dishDetailVO.setMessage(e.getMessage());
            return new Response(4004, dishDetailVO);
        }

        String dishDescriptionTemp = dish.getDishDescription();
        List<DishDescriptionItemVO> descriptionItems = new ArrayList<>();

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            descriptionItems = objectMapper.readValue(dishDescriptionTemp, objectMapper.getTypeFactory().constructCollectionType(List.class, DishDescriptionItemVO.class));
        } catch (JsonProcessingException e) {
            return new Response(4004);
        }
        DishDetailVO dishDetailVO = new DishDetailVO()
                .setCoverImages(BaseUtils.splitByDollar(dish.getCoverImages()))
                .setDishName(dish.getDishName() == null ? "" : dish.getDishName())
                .setDishPrice(dish.getDishPrice() == null ? -1 : dish.getDishPrice())
                .setDishScore(dish.getDishScore() == null ? -1 : dish.getDishScore())
                .setDishIngredients(BaseUtils.splitByDollar(dish.getDishIngredients()))
                .setDishDescription(descriptionItems)
                .setDishReview(BaseUtils.splitByDollar(dish.getDishReview()));

        Category category;
        try {
            category = categoryService.getCategory(dish.getCategoryId());
        } catch (Exception e) {
            dishDetailVO.setCategoryName(e.getMessage());
            dishDetailVO.setCategoryImage(e.getMessage());
            return new Response(4004, dishDetailVO);
        }
        dishDetailVO.setCategoryName(category.getCategoryName() == null ? "" : category.getCategoryName());
        dishDetailVO.setCategoryImage(category.getCategoryImage() == null ? "" : category.getCategoryImage());
        return new Response(1001, dishDetailVO);

    }

    @GetMapping("/dish/export")
    public void exportDishExcel(HttpServletResponse response) throws IOException {
        // 1. 设置响应头：告诉浏览器这是一个 Excel 文件，需要下载
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("菜品列表", "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");

        // 2. 查询原始数据
        List<Dish> dishList = dishService.getAll();

        // 3. 转换为导出用的 VO 列表
        List<DishExportVO> voList = DishConverter.toDishExportVO(dishList);

        // 4. 使用 EasyExcel 写入响应输出流
        EasyExcel.write(response.getOutputStream(), DishExportVO.class)
                .sheet("菜品数据")
                .doWrite(voList);
    }

    @PostMapping("/dish/import")
    public void importDishExcel(@RequestParam("file") MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), DishExportVO.class, new DishImportListener(dishService))
                .sheet()
                .doRead();
    }

    private final ExecutorService executor = Executors.newFixedThreadPool(10);

    @GetMapping("dish/export/zip")
    public ResponseEntity<FileSystemResource> exportDishShardsZip() throws IOException {
        // 1. 创建临时目录
        String tempDirPath = FileUtil.getTmpDirPath() + "/dish_export_" + System.currentTimeMillis();
        File tempDir = FileUtil.mkdir(tempDirPath);

        // 2. 创建 ZIP 文件
        File zipFile = new File(tempDir.getParentFile(), "dish_export_all_" + System.currentTimeMillis() + ".zip");

        try {
            // 3. 提交异步任务
            CompletableFuture<?>[] futures = new CompletableFuture[10];
            for (int mod = 0; mod < 10; mod++) {
                final int finalMod = mod;
                futures[mod] = CompletableFuture.runAsync(() -> {
                    List<Dish> dishList = dishService.getDishShardByMod(finalMod);
                    List<DishExportVO> voList = DishConverter.toDishExportVO(dishList);

                    String fileName = "dish_mod_" + finalMod + ".xlsx";
                    File excelFile = new File(tempDir, fileName);
                    EasyExcel.write(excelFile, DishExportVO.class)
                            .sheet("菜品分片" + finalMod)
                            .doWrite(voList);
                }, executor);
            }

            // 4. 等待所有导出完成
            CompletableFuture.allOf(futures).join();

            // 5. 使用正确的压缩方法
            ZipUtil.zip(tempDir.getAbsolutePath(), zipFile.getAbsolutePath(), false);

            // 6. 设置响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", "attachment; filename=dish_export_all.zip");

            // 7. 返回资源
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(zipFile.length())
                    .body(new FileSystemResource(zipFile));

        } finally {
            // 8. 清理：删除临时目录
            FileUtil.del(tempDir);
            // ZIP 文件不要在这里立即删除，Spring 还在使用
        }
    }

    @PostMapping("/dish/import/zip")
    public ResponseEntity<String> importDishZip(@RequestParam("file") MultipartFile zipFile) throws IOException {
        // 1. 创建独立的临时目录（不与 ZIP 文件混在同一父目录）
        String workDirPath = Files.createTempDirectory("dish_import_").toString();
        File workDir = new File(workDirPath);

        // 2. 将上传的 ZIP 内容写入 workDir 下的 zip 文件（完全由我们控制）
        File zipTarget = new File(workDir, "import.zip");
        try (InputStream in = zipFile.getInputStream();
             FileOutputStream out = new FileOutputStream(zipTarget)) {
            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
        } // ← 确保流关闭！

        try {
            // 3. 解压到 workDir 下的子目录
            File unzipDir = new File(workDir, "unzipped");
            unzipDir.mkdirs();
            ZipUtil.unzip(zipTarget.getAbsolutePath(), unzipDir.getAbsolutePath());

            // 4. 获取所有 Excel 文件
            File[] excelFiles = unzipDir.listFiles((dir, name) -> name.toLowerCase().endsWith(".xlsx"));
            if (excelFiles == null || excelFiles.length == 0) {
                return ResponseEntity.badRequest().body("ZIP 中未找到 Excel 文件");
            }

            // 5. 并发导入
            ExecutorService executor = Executors.newFixedThreadPool(Math.min(excelFiles.length, 10));
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            for (File excel : excelFiles) {
                futures.add(CompletableFuture.runAsync(() -> {
                    try (InputStream is = new FileInputStream(excel)) {
                        EasyExcel.read(is, DishExportVO.class, new DishImportListener(dishService))
                                .sheet()
                                .doRead();
                    } catch (IOException e) {
                        throw new RuntimeException("解析 Excel 失败: " + excel.getName(), e);
                    }
                }, executor));
            }

            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
            executor.shutdown();

            return ResponseEntity.ok("导入成功，共处理 " + excelFiles.length + " 个文件");

        } finally {
            // 6. 安全清理：删除整个 workDir（此时所有文件都已关闭）
            // 使用 Hutool 或 Java NIO 递归删除
            try {
                FileUtil.del(workDir); // Hutool 的 del 会递归删除
            } catch (Exception e) {
            }
        }
    }
}
